import React, { FC } from 'react';
import { Element as SlateElement, NodeEntry, Node, Text } from 'slate';
import { css } from 'emotion';
import { pipe } from 'rambda';

import { CustomText, RenderElementPropsAttributes, RenderLeafPropsAttributes, CodeText, CustomRange } from '../slate';

import { CheckListItem, withChecklists } from './CheckList';
import { Code, codeDecorate } from './Code';
import { CodeBlock, withCodeBlock } from './CodeBlock';
import { Website } from './Website';
import { searchDecorate } from '../../../src/module/Search';
import { withLinks } from './Link';
import { withShortcuts } from './Markdown';

interface LeafProps {
  attributes: RenderLeafPropsAttributes;
  leaf: CustomText | CodeText;
  text: string;
}

export const Leaf: FC<LeafProps> = ({ attributes, children, leaf, text }) => {
  if (leaf.code) {
    return (
      <Code leaf={leaf} attributes={attributes}>
        {children}
      </Code>
    );
  }

  if (leaf.bold) {
    children = <strong>{children}</strong>;
  }

  if (leaf.code) {
    children = <code>{children}</code>;
  }

  if (leaf.italic) {
    children = <em>{children}</em>;
  }

  if (leaf.underline) {
    children = <u>{children}</u>;
  }

  if (leaf.strike) {
    children = <del>{children}</del>;
  }

  return (
    <span
      {...attributes}
      style={{
        color: leaf.color,
        backgroundColor: leaf.highlight ? 'yellow' : leaf.background,
        // TODO: 修改成对应的值
        fontSize: leaf.fontSize,
        fontFamily: leaf.fontFamily,
      }}
    >
      {children}
    </span>
  );
};

interface ElementProps {
  attributes: RenderElementPropsAttributes;
  element: SlateElement;
}

const listStyle = css`
  padding-left: 0;
  list-style-position: inside;
  ul {
    padding-left: 30px;
  }
`;

export const Element: FC<ElementProps> = (props) => {
  const { attributes, children, element } = props;
  switch (element.type) {
    case 'block-quote':
      return (
        <blockquote
          className={css`
            border-left: 2px solid #ddd;
            margin-left: 0;
            margin-right: 0;
            padding-left: 10px;
            color: #aaa;
            font-style: italic;
          `}
          {...attributes}
        >
          {children}
        </blockquote>
      );
    case 'unordered-list':
      return (
        <ul className={listStyle} {...attributes}>
          {children}
        </ul>
      );
    case 'bulleted-list':
      return (
        <ol className={listStyle} {...attributes}>
          {children}
        </ol>
      );
    case 'heading1':
      return <h1 {...attributes}>{children}</h1>;
    case 'heading2':
      return <h2 {...attributes}>{children}</h2>;
    case 'heading3':
      return <h3 {...attributes}>{children}</h3>;
    case 'heading4':
      return <h4 {...attributes}>{children}</h4>;
    case 'heading5':
      return <h5 {...attributes}>{children}</h5>;
    case 'heading6':
      return <h6 {...attributes}>{children}</h6>;
    case 'list-item':
      return <li {...attributes}>{children}</li>;
    case 'check-list':
      return <CheckListItem {...props} element={element} />;
    case 'codeBlock':
      return <CodeBlock {...props} element={element} />;
    case 'website':
      return <Website {...props} element={element} />;
    case 'table':
      return (
        <table>
          <tbody {...attributes}>{children}</tbody>
        </table>
      );
    case 'table-row':
      return <tr {...attributes}>{children}</tr>;
    case 'table-cell':
      return <td {...attributes}>{children}</td>;
    case 'link':
      return (
        <a
          {...attributes}
          onMouseDown={(e) => {
            window.open(e.currentTarget.text);
          }}
        >
          {children}
        </a>
      );
    case 'indent':
      const { data } = element;
      return (
        <div
          className={css`
            text-indent: ${2 * data}em;
          `}
        >
          {children}
        </div>
      );
    default:
      return <p {...attributes}>{children}</p>;
  }
};

export const allDecorate = (entry: NodeEntry<Node>) => [...searchDecorate(entry), ...codeDecorate(entry)];

export const withEditor = pipe(withChecklists, withCodeBlock, withLinks, withShortcuts);
